package pt.isel.pdm.ouryamba;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class StatusUploadService extends Service implements Runnable
{
	
	public static final String ARG_STATUS = "status";
	private General app;
	private Thread worker_thread;
	private final String THREAD_NAME = ID + "_worker_thread"; 
	private final BlockingQueue<Intent> queue = new LinkedBlockingQueue<Intent>();
	public final static String ID = StatusUploadService.class.getName();
	private final Integer DEFAULT_TOKEN_VALUE = -1;
	public static final String ARG_TOKEN = "onSuccessToken";
	
	
//Service methods
	
	/**
	 * Since this is a started service, the is no object to bind.
	 * */
	@Override
	public IBinder onBind(Intent arg0) 
	{
		return null;
	}

	/**
	 * Starts the background worker thread and stores a reference for the Application instance. 
	 * */
	@Override
	public void onCreate()
	{
		super.onCreate();
		worker_thread = new Thread(this, THREAD_NAME);
		worker_thread.start();
		app = (General) getApplication();
	}

	/**
	 * Stops the background worker thread and reference it to null (helps the GC).
	 * */
	@Override
	public void onDestroy() 
	{
		worker_thread.interrupt();
		worker_thread = null;
		super.onDestroy();
	}

	/**
	 * Add the new intent to the queue of intents (thread safe).
	 * 
	 * @return The flag START_NOT_STICKY which means the service should not be restarted after
	 * Android killed the service for memory usage.
	 * */
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) 
	{
		queue.add(intent);
		return START_NOT_STICKY;
	}

	
//Runnable methods
	
	/**
	 * Upload the status through the worker thread.
	 * 
	 * Fetch one intent from the queues of intents, extract the status and the token (for further use)
	 * and upload the status to the server. The token is later used to notify the "waiters" 
	 * (IMyListener instances inside the General.toNotifyList) to identify the one who sent this 
	 * intent.
	 * After the notification the service stop itself, guarantee that no matter which or none activity
	 * is being show, the status is uploaded.
	 * 
	 * @see General#getTwitter()
	 * @see General#log(String)
	 * @see IMyListener#onSuccess(Integer)
	 * */
	@Override
	public void run() 
	{
		try
		{
			Intent intent;
			String status;
			Integer token;
			while(queue.size() != 0)
			{
				intent = queue.take();
				if(intent == null)
				{
					app.log("StatusUploadService.worker_thread.run(): The intent fetched is null.");
					throw new InterruptedException();
				}
				status = intent.getStringExtra(ARG_STATUS);
				if(status == null)
				{
					app.log("StatusUploadService.worker_thread.run(): The intent hasn't the status extra.");
					throw new InterruptedException();
				}
				token = intent.getIntExtra(ARG_TOKEN, DEFAULT_TOKEN_VALUE);
				if(token == DEFAULT_TOKEN_VALUE)
				{
					app.log("StatusUploadService.worker_thread.run():The token was not sent as argument.");
					throw new InterruptedException();
				}
				else
				{
					if(app.getTwitter().isValidLogin())
					{
						app.getTwitter().updateStatus(status);
						app.log("Status sent");
						for(IMyListener waiter : app.toNotifyList)
						{
							if(waiter instanceof StatusActivity)
							{
								waiter.onSuccess(token);
							}
						}
					}			
				}
			}
			stopSelf();
		}
		catch (InterruptedException e)
		{
			app.log("StatusUpdloadService.worker_thread.run(): Thread interrupted.");
		}
		catch (Exception e)
		{
			app.log("StatusUpdloadService.worker_thread.run(): Exception thrown.");
			app.log(e.getMessage());
		}
	}
	
}
